<?php
/**
 * CModel class file.
 * 模型基类.
 * @author Huan Song <iphper@yeah.net>
 * @version $Id: CModel.php 1 2011-03-03 19:18:34Z huan.song $
 * @package system.model
 * @since 2.0
 */
class CModel extends CApplication
{
	/**
	 * @var array 所有的错误记录.
	 */
    protected $_errors = array();
	
    /**
	 * 常量: 插入操作.
	 */
	const INSERT = 1;
	
	/**
	 * 常量: 修改操作.
	 */
	const UPDATE = 2;
	
	/**
	 * 常量: 插入和修改操作.
	 */
	const BOTH = 3;
    
    /**
	 * 自动验证表单.
	 * <pre>
	 * class UsersModel extends CTable {}
	 * 
	 * $model = new UsersModel();
	 * $attributes = $_POST;
	 * $hasError = $model->validate($attributes);
	 * </pre>
	 * @param array $attributes 表单数据，如果为空，默认从$this->_attributes中取值.
	 * @return boolean 表单数据是否正确.
	 */
	public function validate($attributes = null)
	{
		$this->_errors = array();
		
		if (null === $attributes)
    		$attributes = $this->getAttributes();
		
		$do = $this->getIsNewRecord() ? self::INSERT : self::UPDATE;
		
		$file = FRAMEWORK_DIR . '/validators/';
		
		foreach ($this->rules as $field => $rule) 
		{
			if (array_key_exists('when', $rule) && 
				$rule['when'] !== self::BOTH && 
				$rule['when'] !== $do) continue;
			
			$value = array_key_exists($field, $attributes) ? $attributes[$field] : null;
			
			foreach ($rule as $method => $arg)
			{
				if (strcasecmp('when', $method) === 0) 
					continue;
				
				$func = 'F' . ucfirst($method) . 'Validator';
				require_once $file . $func . '.php';
				if (!$func($this, $attributes, $field, $arg))
				{
					$this->addError($field, $this->messages[$field][$method]);
					break;
				}
			}
		}
		
		return $this->hasError();
	}
    
 	/**
     * 添加一条错误记录.
     * <pre>
	 * class UsersModel extends CTable {}
	 * 
	 * $model = new UsersModel();
	 * $model->addError('username', '此用户名已被使用');
	 * $model->addError('email', '邮箱格式不正确');
	 * </pre>
     * @param string $key 字段名.
     * @param string $val 字段值.
     * @return void
     */
    public function addError($key, $val)
    {
        if (array_key_exists($key, $this->_errors)) 
        {
            if (!is_array($this->_errors[$key]))
                $this->_errors[$key] = array($this->_errors[$key]);
			
            $this->_errors[$key][] = $val;
        }
        else
            $this->_errors[$key] = $val;
    }
    
	/**
     * 通过键名获取一条错误信息. 如果键名为空, 返回第一条错误信息.
     * <pre>
	 * class UsersModel extends CTable {}
	 * 
	 * $model = new UsersModel();
	 * $error = $model->getError('username');
	 * 结果: '此用户名已被使用'
	 * 
	 * $error = $model->getError('email');
	 * 结果: '邮箱格式不正确'
	 * 
	 * $error = $model->getError();
	 * 结果: 第一个错误'此用户名已被使用'
	 * 
	 * $error = $model->getError('password');
	 * 结果: null
	 * </pre>
     * @param string $key
     * @return string|null 错误记录.
     */
    public function getError($key = null)
    {
    	if (empty($this->_errors))
    		return null;
    	
    	if (null === $key)
    		return array_shift(array_slice($this->_errors, 0, 1));
    	
        if ($this->hasError($key))
            return $this->_errors[$key];
		
        return null;
    }
	
    /**
     * 返回所有的错误信息.
     * <pre>
	 * $errors = $model->getErrors();
	 * </pre>
     * @return array 所有的错误信息.
     */
    public function getErrors()
    {
        return $this->_errors;
    }
    
	/**
     * 判读某个错误记录是否存在.
     * <pre>
	 * $hasError = $model->hasError('username');
	 * $hasError = $model->hasError();
	 * </pre>
     * @param string $key
     * @return boolean
     */
    public function hasError($key = null)
    {
        if (null === $key)
            return count($this->_errors) > 0;

        return array_key_exists($key, $this->_errors);
    }
}